<?php
namespace App\Models\Traits;
use Illuminate\Support\Facades\Cache;

trait Filters
{
    /**
     * Add defaultSort .
     * 
     * @return array||string
     */
    //列表显示
    protected $listFields=[];
    //列表隐藏，如内容等大字节字段
    protected $listHidden = [];

    //列表默认索引 ['id'=>'desc','title'=>'asc']
    protected $sort = [];
    //允许索引字段
    protected $allowedSort=[];
    //允许索引字段
    protected $disableSort=[];
    /**
     * 列表允许关联(指明模型) 例 
     * $listWith = [
     *  'posts'     =>'App\Models\Post',
     *  'posts.user'=>'App\Models\User',
     * ];
     * @var array
     * @Author 老蟹 7040867@qq.com    DateTime 2020-01-11
     */
    
    protected $listWith = [];

    //快速检索 例q
    protected $fastFilter=[];
    //不允许过滤
    protected $disableFilter=[];

    //默认列表设置
    protected $listSet=[
            'fields'=>['aa','bb'],
            'filter'=>['status'=>1],
            'includes' => ['posts','posts.user'],
            'posts' =>[
                'fields'=>['id,user_id','cate_id','title'],
                'limit' =>10,
                'sort'  =>['created_at','desc']
            ],
            'posts.user' => [
                'fields' => ['id','name'],
            ],
        ];

    public function getlistSet(){  
        $set['sort']   = $this->sort;
        $set['select'] = $this->getListFields();
        $set['with'] = $this->getIncludes();
        $set['sorts']  = $this->getSorts();
        $set['fields'] = $this->getAllFields();
        $set['filters']= $this->getFilters();
        $set['appends']= $this->appends;
        return $set;
    }

    /**
     * filters过滤
     * @$search 检索模式
     * $search=false时,$select,$include相关无效
     */
    public function scopeFilters($query,$search=false,$request=false)
    {        
        $error = [];        
        if($request===false) $request = request()->all();
        if(!is_array($request)) $request=[];
        if($search){
            $request = array_merge($this->getList(),$request);
        }else{
            $request = array_merge($request,$this->getList());
        }

        if($search && $select=$request->get('select','')){
            $select   = $select ?: array_intersect(str2arr($select),$this->getListFields());
        }else{
            $select   = $this->getListFields();
        }

        $query = $query->select($select);

        $filters  = $request->get('filter','');

        $allowedFilter = $this->getAllowedFilters();

        if(is_array($filters)){
            $query = filter($query,$filters,$allowedFilter);  
        }

        if($search && $include_str = $request->get('include','')){
            if($include_str=='null'){
                $includes = [];
            }else{
                $includes = array_intersect(str2arr($include_str),$this->includes);
            }
        }else{
            $includes = array_intersect(str2arr($include_str),$this->getListIncludes());
        }
        
        foreach ($includes as $key => $v){
            //参数名不能有.,所以将.改成-,如posts.user改成posts-user;
            $q = str_replace('-','.',$v);
            $qs = str2arr($q,'.');
            $req = $request->get($q,'');
            if(!is_array($req)) continue;
            $wfilters   = $req['filter'] ?? [];
            $wselect    = $req['select'] ?? [];

            foreach ($includes as $v) {
                $q = empty($req[$v]) ? [] : $req[$v];
                
                if($q && is_array($q)){ 
                    $withs[$v] = function($query) use($q,$v){
                        return $query = with_query($query,$q,$v);
                    };                  
                }else{
                    $withs[] = $v;
                }
            }
            //$date = $data->with($withs);
        }


        return $query;
    }
  




    /**
     * 可with关联
     */
    public function setIncludes($withs=[]){
        $this->includes = $withs;
    }
    public function getWith($mothed){
        static $models=[];
        $arr = str2arr($mothed,'.');
        for ($i=0; $i < count($arr); $i++) {
            if($i==0 && empty($models[$arr[0]])){
                $models[$arr[0]]['model']
            }



            $k = arr2str(array_chunk($arr,$i+1));
            if(empty($models[$k]) && $i ==0){

            }
        } 
        
        foreach ($arr as $key => $v) {
            $models[]=$k$v;
        }
        /*
        //无法识别带点关联
        $includes = $this->includes;
        foreach ($includes as $k=>$with) {
            try {
                get_class($this->$with());
                if($getit){
                    $wf = $model->getFields();
                    $wf = array_map(function($v) use($with){
                                                return $with.'.'.$v;
                                            },$wf);
                    $this->allfields = array_merge($this->allfields,$wf);
                }
            }catch (\Exception $e){
                unset($this->includes[$k]);
            }
        }
        if(is_null($includes)) $includes = [];
        */
        return $this->includes;
    }    




    //以下为关联相关
    //列表时允许使用的关联
	public function setListWith(array $motheds)
	{
        $this->listWith = $motheds;
    }
    
    /**
     * 可索引字段
     */
    //以下为索引字段设置 添加 $listFields,$listHidden
	public function setAllowedSort(array $fields)
	{
        $this->allowedSort = $fields;
    }  
	public function setDisableSort(array $fields)
	{
        $this->disableSort = $fields;
    }  
	public function getAllowedSort(array $fields)
	{
        if($this->allowedSort){
            return $this->allowedSort;
        }else{
            return array_diff($this->getTableFields(),$this->disableSort);
        }
    }
    
    //以下为检索字段设置 添加 $disableFilter
	public function getAllowedFilters()
	{       
        return array_diff($this->getTableFields(),$this->disableFilter);
    }

	public function setDisableFilter(array $fields)
	{
        $this->disableFilter = $fields;
    }  


    //以下为字段设置 添加 $listFields,$listHidden
	public function setListHidden(array $fields)
	{
        $this->listHidden = $fields;
    }  
	public function setListFields(array $fields)
	{
        $this->listFilter = $fields;
    }  

    /**
     * 模型表字段
     */
    public function getTableFields($refrech=false){
        $table = $this->getTable();
        if($refrech || empty(Cache::get('table-fields-'.$table))){	
            $fields = \Illuminate\Support\Facades\Schema::getColumnListing($table);			
			Cache::forever('table-fields-'.$table,$fields);
        }else{
            $fields = Cache::get('table-fields-'.$table);
        }        
        return $fields;
    }        

    //所有字段
    public function getAllFields(){
        return array_merge($this->getTableFildes,$this->appends);
    }

    /**
     * 模型所有可显示字段
     */
    public function getAllowedFields($model = false)
    {
        if($this->getVisible()){
            return $this->getVisible();
        }else{            
            return array_diff($this->getAllFields(),$this->hidden);
        }
    }

    /**
     * 列表时默认显示字段
     * $listFields
     * $listHidden
     */  
    public function getListFields()
    {
        if($this->listFields){
            return $this->listFields;
        }else{
            return array_diff($this->getAllowedFields(), $this->listHidden);
        }
    }
}